#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import hashlib
import logging
import re
import time

from aiohttp import web

from com.chenxiaojie.config.config import configs
from com.chenxiaojie.model.user import User
from com.chenxiaojie.mvc.error import APIValueError, APIError
from com.chenxiaojie.mvc.mvc import get, post
from com.chenxiaojie.myjson.myjson import to_json_str

_RE_EMAIL = re.compile(r'^[a-z0-9\.\-\_]+\@[a-z0-9\-\_]+(\.[a-z0-9\-\_]+){1,4}$')
_RE_SHA1 = re.compile(r'^[0-9a-f]{40}$')
_COOKIE_NAME = 'chenxiaojiesession'
_COOKIE_KEY = configs.session.secret


def user2cookie(user, max_age):
    expires = str(int(time.time() + max_age))
    s = '%s-%s-%s-%s' % (user.id, user.passwd, expires, _COOKIE_KEY)
    l = [user.id, expires, hashlib.sha1(s.encode('utf-8')).hexdigest()]
    return '-'.join(l)


async def cookies2user(cookies):
    return await cookie2user(cookies.get(_COOKIE_NAME))


async def cookie2user(cookie_str):
    if not cookie_str:
        return None
    try:
        L = cookie_str.split('-')
        if len(L) != 3:
            return None
        uid, expires, sha1 = L
        if int(expires) < time.time():
            return None
        user = await User.find(uid)
        if user is None:
            return None
        s = '%s-%s-%s-%s' % (uid, user.passwd, expires, _COOKIE_KEY)
        if sha1 != hashlib.sha1(s.encode('utf-8')).hexdigest():
            return None
        user.passwd = '******'
        return user
    except Exception as e:
        return None


@get('/user/register.html')
def register():
    return {
        '__template__': 'register.html'
    }


@get('/user/login.html')
async def login(request):
    return {
        '__template__': 'login.html'
    }


@post('/user/login')
async def user_login(*, email, passwd):
    if not email:
        raise APIValueError('email', 'Invalid email.')
    if not passwd:
        raise APIValueError('passwd', 'Invalid password.')
    users = await User.findAll('email=?', [email])
    if len(users) == 0:
        raise APIValueError('email', 'Email not exist.')
    user = users[0]
    # check passwd:
    sha1 = hashlib.sha1()
    sha1.update(user.id.encode('utf-8'))
    sha1.update(b':')
    sha1.update(passwd.encode('utf-8'))
    if user.passwd != sha1.hexdigest():
        raise APIValueError('passwd', 'Invalid password.')
    # authenticate ok, set cookie:
    r = web.Response()
    r.set_cookie(_COOKIE_NAME, user2cookie(user, 86400), max_age=86400, httponly=True)
    user.passwd = '******'
    r.content_type = 'application/json'
    r.body = to_json_str(user)
    return r


@get('/user/logout')
async def logout(request):
    referer = request.headers.get('Referer')
    r = web.HTTPFound(referer or '/')
    r.set_cookie(_COOKIE_NAME, '-deleted-', max_age=0, httponly=True)
    logging.info('user logout')
    return r


@post('/user')
async def add_user(*, email, name, passwd):
    if not name or not name.strip():
        raise APIValueError('name')
    if not email or not _RE_EMAIL.match(email):
        raise APIValueError('email')
    if not passwd or not _RE_SHA1.match(passwd):
        raise APIValueError('passwd')
    users = await User.findAll('email=?', [email])
    if len(users) > 0:
        raise APIError('register:failed', 'email', 'Email is already in use.')
    user = User(name=name.strip(),
                email=email,
                image='/static/img/user.png')

    await user.insert()
    sha1_passwd = '%s:%s' % (user.id, passwd)
    user.passwd = hashlib.sha1(sha1_passwd.encode('utf-8')).hexdigest()
    await user.update()

    r = web.Response()
    r.set_cookie(_COOKIE_NAME, user2cookie(user, 86400), max_age=86400, httponly=True)
    user.passwd = '******'
    r.content_type = 'application/json'
    r.body = to_json_str(user)
    return r


@get('/user/test')
async def template():
    users = await User.findAll()

    return {
        '__template__': 'test.html',
        'users': users
    }
